﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Reactive.Concurrency;
using System.Reactive.Threading;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Windows.Markup;

using alib;
using alib.Memory;
using alib.file;
using alib.Collections.ReadOnly;
using alib.Debugging;
using alib.Enumerable;
using alib.Reflection;

#pragma warning disable 0649

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class sysobj_info : namescope_helper
	{
		static sysobj_info()
		{
			c_phys_cpus = Kernel32.PhysicalProcessorCores;

			c_log_cpus = Environment.ProcessorCount;

			msex = Kernel32.MemoryStatus;

			s_cpu_inf = String.Format("{0:#.##}GB {1} CPUs{2}, x{3} gc={4}",
					msex.ullTotalPhys / alib.Int._int_ext.GigabyteD,
					c_log_cpus,
					c_phys_cpus != c_log_cpus ? "" : String.Format(" ({0} cores)", c_phys_cpus),
					IntPtr.Size == 8 ? "64" : "86",
					System.Runtime.GCSettings.IsServerGC ? "Server" : "Workstation");
		}

		static readonly Kernel32.MEMORYSTATUSEX msex;

		static readonly int c_phys_cpus;
		public static int PhysicalCPUs { get { return c_phys_cpus; } }

		static readonly int c_log_cpus;
		public static int LogicalCPUs { get { return c_log_cpus; } }

		static readonly String s_cpu_inf;
		public static String CpuInfo { get { return s_cpu_inf; } }

	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class sysobj_settings : sysobj_info
	{
		public sysobj_settings()
		{
			this.Settings = new _settings(null);
		}

		public _settings Settings;

		public void set_settings(ApplicationSettingsBase set)
		{
			this.Settings = new _settings(set);
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class sysobj_services : sysobj_settings, IRtParent, schema.ρρName
	{
		public sysobj_services()
		{
			this.tc = new TaskController(this, TaskPoolScheduler.Default);
		}

		public IIdentity Trace { get { return null; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		readonly TaskController tc;
		public TaskController TaskControl { get { return tc; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public INameScope NameScope { get { return this; } }

		public Object GetService(System.Type Tsvc)
		{
			return this.GetType().IsAssignableFrom(Tsvc) ? this : null;
		}

		public String Name
		{
			get { return "agree system instance"; }
			set { throw not.valid; }
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	///
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class sysobj_idle_block : sysobj_services
	{
		static sysobj_idle_block()
		{
			c_global_tasks = 0;
			mre = new ManualResetEvent(false);
		}

		alib.Concurrency.FalseSharing.Padding60 fsp1;
		static long c_global_tasks;
		alib.Concurrency.FalseSharing.Padding60 fsp2;
		static long c_total_tasks;

		public static long GlobalTaskCount { get { return c_global_tasks; } }

		static readonly ManualResetEvent mre;

		public static long BeginApplicationTask()
		{
			Interlocked.Increment(ref c_total_tasks);

			long c;
			if ((c = Interlocked.Increment(ref c_global_tasks)) == 1)
				mre.Reset();
			return c;
		}
		public static void EndApplicationTask()
		{
			long c;
			if ((c = Interlocked.Decrement(ref c_global_tasks)) < 0)
				throw new Exception();
			else if (c == 0)
				mre.Set();
		}

		public static void Idle() { mre.WaitOne(); }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[UsableDuringInitialization(true)]
	public class SysObj : sysobj_idle_block, schema.ρρDefaultDirectories
	{
		public static readonly SysObj Instance;

		static SysObj()
		{
			new SysObj(out Instance);

			System.Text.RegularExpressions.Regex.CacheSize = 500;
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		SysObj(out SysObj _inst)
		{
			_inst = this;
			this.dps = new DirectoryPathSet(this);
		}

		public TextWriter tw_debug { get; set; }

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		DirectoryPathSet dps;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public DirectoryPathSet DefaultDirectories
		{
			get { return dps; }
			set
			{
				if (value == null || value.Count == 0)
					return;
				if (dps.Count > 0)
					throw not.impl;
				dps = value;
			}
		}

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		assembly_stats astats_core { get { return schema.Schema.rg_astats[0]; } }

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public String FindDefaultXamlFile(String fn)
		{
			String dir = Path.GetDirectoryName(astats_core.asm.Location);
			String stop = Environment.CurrentDirectory;
			String full;

			while (!String.IsNullOrEmpty(dir))
			{
				if (File.Exists(full = Path.Combine(dir, fn)))
					return full;

				if (dir == stop)
					break;

				dir = Path.GetDirectoryName(dir);
			}
			throw new FileNotFoundException("Xaml file not found: " + fn, fn);
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// 
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public Type[] ListOfFunctorMonads()
		{
			return astats_core
						.asm
						.DefinedTypes
						.Select(ti => ti.AsType())
						.Where(t => t.FindGenericInterface(typeof(IMonad<,>)) != null &&
									t.FindGenericInterface(typeof(IFunctor<,>)) != null)
						.ToArray();
		}
	};
}
